﻿//-------------------------------------
// WBFSSync - WBFSSync.exe
//
// Copyright 2009 Caian (ÔmΣga Frøst) <frost.omega@hotmail.com> :
//
// WBFSSync is Licensed under the terms of the Microsoft Reciprocal License (Ms-RL)
//
// QuickLink.cs:
//
// Controle que imita os botões da barra de atalhos do Explorer do Windows Vista e Seven
//
//-------------------------------------

using System;
using System.Collections.Generic;
using System.ComponentModel;
using System.Drawing;
using System.Data;
using System.Linq;
using System.Text;
using System.Windows.Forms;
using System.Drawing.Drawing2D;

namespace WBFSSync.AeroControls
{
    public partial class QuickLink : UserControl
    {
        //----------------------- Constantes

        public const int SevenLeftMarginStart = 19; //A margem de desenho no Windows Seven
        public const int SevenLeftMarginAdd = 10; //O aumento da margem de desenho por sub-item no Windows Seven

        //----------------------- Variáveis

        Image linkimage = null; //O ícone do link

        Image specialimage = null; //O ícone especial
        Image specialimageOver = null; //O ícone especial, quando o mouse está sobre ele

        String linktext = ""; //O texto do link

        Boolean drawimage = true; //Desenha o link com ou sem o ícone

        Brush foreBrush = null;

        Int32 level = 0; //O nível de sub-item, 
                         //iconDrawPos_x e textDrawPos_x = SevenLeftMarginStart + level*SevenLeftMarginAdd

        Int32 iconDrawPos_x = 0; //A posição de referência para desenhar o ícone
        Int32 iconDrawPos_y = 0; //

        Int32 textDrawPos_x = 0; //A posição de referência para desenhar o texto
        Int32 textDrawPos_y = 0; //

        Int32 specialIconDrawPos_x = 0; //A posição de referência para desenhar um dos ícones especiais
        Int32 specialIconDrawPos_y = 0; //

        Boolean mouse_in_control = false; //Irá desenhar o fundo quando o mouse estiver dentro da área do controle
        Boolean control_clicked = false; //O controle foi clicado pelo mouse

        Boolean mouse_in_special = false; //Icone especial sob o ponteiro do mouse
        Boolean special_clicked = false; //O Icone especial foi clicado pelo mouse

        QuickLinksPanel parent = null;

        Point mousePosition = new Point(-1, -1);

        ToolTip specialTooltip = new ToolTip();
        String tooltiptext = "";

        StringFormat textFormat = new StringFormat();

        public Image Icon { get { return linkimage; } set { linkimage = value; OnIconChanged(); } }
        public Image SpecialIcon { get { return specialimage; } set { specialimage = value; OnSpecialIconChanged(); } }
        public Image SpecialIconOver { get { return specialimageOver; } set { specialimageOver = value; OnSpecialIconChanged(); } }
        public new String Text { get { return linktext; } set { linktext = value; OnTextChanged(); } }
        public Boolean Clicked { get { return control_clicked; } set { control_clicked = value; OnClickedStateChanged(); } }
        public Boolean ShowIcon { get { return drawimage; } set { drawimage = value; OnShowIconChanged(); } }
        public Int32 Level { get { return level; } set { level = value; OnLevelChanged(); } }

        public String TooltipText { get { return tooltiptext; } set { tooltiptext = value; OnToolTipTextChanged(); } }

        public event EventHandler SpecialClick;

        //----------------------- Rotinas

        //----------------- Construtor
        public QuickLink(QuickLinksPanel parent)
        {
            this.parent = parent;
            InitializeComponent();
            foreBrush = new SolidBrush(ForeColor);

            textFormat.Trimming = StringTrimming.EllipsisCharacter;

            specialIconDrawPos_x = Width - 18;
            specialIconDrawPos_y = (Height - 11) / 2;

            iconDrawPos_x = SevenLeftMarginStart + SevenLeftMarginAdd * level;
            iconDrawPos_y = (Height - 16) / 2;

            textDrawPos_x = SevenLeftMarginStart + 16 + 5 + SevenLeftMarginAdd * level;
            textDrawPos_y = (Height - Skin.CaptionFont.Height) / 2;
        }

        //----------------- Verifica se o mouse está dentro de uma determinada região
        public bool CheckMouseIntersection(int x, int y, int w, int h)
        {
            return ((mousePosition.X >= x) && (mousePosition.X < x + w) &&
                    (mousePosition.Y >= y) && (mousePosition.Y < y + h));
        }

        //----------------- Override para desenhar o controle
        protected override void OnPaint(PaintEventArgs e)
        {
            e.Graphics.SmoothingMode = SmoothingMode.HighSpeed;
            e.Graphics.InterpolationMode = InterpolationMode.NearestNeighbor;
            e.Graphics.PixelOffsetMode = PixelOffsetMode.HighQuality;

            //Desenha o fundo
            if (control_clicked)
            {
                if (Focused)
                {
                    e.Graphics.DrawImage(Skin.quicklink_l_c, 0, 0, 3, 21);
                    e.Graphics.DrawImage(Skin.quicklink_m_c, 3, 0, Width - 6, 21);
                    e.Graphics.DrawImage(Skin.quicklink_r_c, Width - 3, 0, 3, 21);
                }
                else
                {
                    e.Graphics.DrawImage(Skin.quicklink_l_oc, 0, 0, 3, 21);
                    e.Graphics.DrawImage(Skin.quicklink_m_oc, 3, 0, Width - 6, 21);
                    e.Graphics.DrawImage(Skin.quicklink_r_oc, Width - 3, 0, 3, 21);
                }
            }
            else
            {
                if (mouse_in_control)
                {
                    e.Graphics.DrawImage(Skin.quicklink_l_o, 0, 0, 3, 21);
                    e.Graphics.DrawImage(Skin.quicklink_m_o, 3, 0, Width - 6, 21);
                    e.Graphics.DrawImage(Skin.quicklink_r_o, Width - 3, 0, 3, 21);
                }
            }

            //Desenha o ícone
            if ((drawimage)&&(linkimage != null))
            {
                e.Graphics.DrawImage(linkimage, iconDrawPos_x, iconDrawPos_y, 16, 16);
            }

            //Desenha o texto
            if (linktext != String.Empty)
            {
                RectangleF textRect = new RectangleF(textDrawPos_x, textDrawPos_y,
                    (((specialimage != null) && (specialimageOver != null)) ? Width - 18 : Width) - textDrawPos_x,
                    Skin.CaptionFont.Height);

                e.Graphics.DrawString(linktext, Skin.CaptionFont, foreBrush, textRect, textFormat);
            }

            if ((specialimage != null) && (specialimageOver != null))
            {
                if ((mouse_in_special) && (!special_clicked))
                {
                    e.Graphics.DrawImage(specialimageOver, specialIconDrawPos_x, specialIconDrawPos_y, 11, 11);
                }
                else
                {
                    e.Graphics.DrawImage(specialimage, specialIconDrawPos_x, specialIconDrawPos_y, 11, 11);
                }
            }

            //Desenha o ícone especial

            base.OnPaint(e);
        }

        //----------------- OnEvents...

        //----------------- Quando o texto muda
        private void OnTextChanged()
        {
            this.Invalidate();
        }
        
        //----------------- Quando a imagem do link muda
        private void OnIconChanged()
        {
            this.Invalidate();
        }
        
        //----------------- Quando o ícone especial do link muda
        private void OnSpecialIconChanged()
        {
            this.Invalidate();
        }

        //----------------- Quando o estado de Click muda
        private void OnClickedStateChanged()
        {
            this.Invalidate();
        }

        private void OnShowIconChanged()
        {
            if (drawimage)
            {
                textDrawPos_x = SevenLeftMarginStart + 16 + 5 + SevenLeftMarginAdd * level;
            }
            else
            {
                textDrawPos_x = SevenLeftMarginStart + SevenLeftMarginAdd * level;
            }
        }
        
        //----------------- Quando o estado de Click muda
        private void OnLevelChanged()
        {
            iconDrawPos_x = SevenLeftMarginStart + SevenLeftMarginAdd * level;

            if (drawimage)
            {
                textDrawPos_x = SevenLeftMarginStart + 16 + 5 + SevenLeftMarginAdd * level;
            }
            else
            {
                textDrawPos_x = SevenLeftMarginStart + SevenLeftMarginAdd * level;
            }

            this.Invalidate();
        }

        //----------------- Quando a dica muda
        private void OnToolTipTextChanged()
        {
            specialTooltip.SetToolTip(this, tooltiptext);
            specialTooltip.Active = false;
        }

        //----------------- Quando o controle perde o foco
        protected override void OnLostFocus(EventArgs e)
        {
            this.Invalidate();
            base.OnLostFocus(e);
        }

        //----------------- Override para quando o tamanho do controle muda
        protected override void OnSizeChanged(EventArgs e)
        {
            base.OnSizeChanged(e);

            specialIconDrawPos_x = Width - 18;
            specialIconDrawPos_y = (Height - 11) / 2;

            this.Invalidate();
        }

        //----------------- Override para quando o mouse entra na area do controle
        protected override void OnMouseEnter(EventArgs e)
        {
            mouse_in_control = true;
            this.Invalidate();
            base.OnMouseEnter(e);
        }

        //----------------- Override para quando o mouse sai da area do controle
        protected override void OnMouseLeave(EventArgs e)
        {
            mouse_in_control = false;
            mouse_in_special = false;
            this.Invalidate();
            base.OnMouseLeave(e);
        }

        //----------------- Override para quando o mouse clica no controle
        protected override void OnMouseDown(MouseEventArgs e)
        {
            if (e.Button != MouseButtons.Left) return;

            if (mouse_in_special)
            {
                special_clicked = true;
            }
            else
            {
                special_clicked = false;
                control_clicked = true;
            }
            parent.BroadcastClick(this);
            this.Invalidate();
            base.OnMouseDown(e);
        }

        //----------------- Override para quando o mouse clica no controle
        protected override void OnClick(EventArgs e)
        {
            if (special_clicked)
            {
                if (SpecialClick != null) SpecialClick(this, null);
            }
            else
            {
                base.OnClick(e);
            }
        }

        protected override void OnMouseUp(MouseEventArgs e)
        {
            special_clicked = false;
            this.Invalidate(new Rectangle(specialIconDrawPos_x, specialIconDrawPos_y, 11, 11));
            base.OnMouseUp(e);
        }

        //----------------- Override para quando o mouse se move na area do controle
        protected override void OnMouseMove(MouseEventArgs e)
        {
            base.OnMouseMove(e);
            mousePosition = new Point(e.X, e.Y);
            if (specialimage != null)
            {
                bool v = CheckMouseIntersection(specialIconDrawPos_x, specialIconDrawPos_y, 11, 11);
                if (v != mouse_in_special)
                {
                    mouse_in_special = v;
                    specialTooltip.Active = v;

                    Invalidate();
                }
            }
        }
    }
}
